﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TinyEngine.Core.Components;

namespace TinyEngine.Core.Services
{
    public class AssemblyService : ITinyService
    {
        private List<Assembly> assemblies = new List<Assembly>();
        private Dictionary<string, Type> entityTypes = new Dictionary<string, Type>();
        private Dictionary<string, Type> componentTypes = new Dictionary<string, Type>();
        
        public List<Type> ComponentTypes
        {
            get
            {
                var list = new List<Type>();
                list.AddRange(componentTypes.Values.ToArray());
                return list;
            }
        }

        public List<Type> EntityTypes
        {
            get
            {
                var list = new List<Type>();
                list.AddRange(entityTypes.Values.ToArray());
                return list;
            }
        }
        
        public void Register()
        {
            RegisterAssembly(typeof(AssemblyService).Assembly);

            if (TinyGame.Instance != null)
            {
                var mainAssembly = TinyGame.Instance.GetType().Assembly;
                RegisterAssembly(mainAssembly);
            }
        }

        private void FindComponents(Assembly item)
        {
            foreach (var type in item.GetTypes())
            {
                if (type.GetInterface(typeof(ITinyComponent).FullName, false) != null)
                {
                    componentTypes.Add(type.Name, type);
                }
            }
        }

        public void UnRegister()
        {
            
        }

        public ITinyComponent CreateComponent(string name, IEntity entity)
        {
            var type = componentTypes[name];
            var instance = Activator.CreateInstance(type, entity);
            return instance as ITinyComponent;
        }

        public void RegisterAssembly(Assembly asm)
        {
            if (assemblies.Contains(asm))
                return;

            Type[] types = null;
            try
            {
                types = asm.GetTypes();
            }
            catch { return; }

            assemblies.Add(asm);

            foreach (var type in types)
            {
                if (entityTypes.ContainsKey(type.Name))
                    continue;

                if(type.GetInterface(typeof(IEntity).FullName, false) != null)
                {
                    entityTypes.Add(type.Name, type);
                }
            }

            FindComponents(asm);
        }

        internal Type FindEntityType(string name)
        {    
            return entityTypes[name];
        }
    }
}
